package graph;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.caliper.Json;
import com.google.caliper.MeasurementType;
import com.google.caliper.Result;
import com.google.caliper.Scenario;
import com.google.caliper.ScenarioResult;

public class ResultsParser {
	// TODO code van stackoverflow
	// http://stackoverflow.com/questions/326390/how-to-create-a-java-string-from-the-contents-of-a-file

	public Result result;

	public ResultsParser(String filename) {
		try {
			result = readResult(filename);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private String readFile(String path) throws IOException {

		FileInputStream stream = new FileInputStream(new File(path));
		try {
			FileChannel fc = stream.getChannel();
			MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0,
					fc.size());
			/* Instead of using default, pass in a decoder. */
			return Charset.defaultCharset().decode(bb).toString();
		} finally {
			stream.close();
		}
	}

	private Result readResult(String filepath) throws IOException {
		return Json.getGsonInstance()
				.fromJson(readFile(filepath), Result.class);
	}
	
	private double arrayMean(List<Double> results){
		int res = 0;
		for (int i = 0; i < results.size(); i++) {
			res += results.get(i);
		}
		return res / results.size();
	}


	public double getBenchmarkMean(String benchmark, String lib) {
		List<Double> results =  new ArrayList<Double>();
		
		for (Map.Entry<Scenario, ScenarioResult> entry : result.getRun().getMeasurements().entrySet()) {
			if (entry.getKey().getVariables().values().contains(benchmark)
					&& entry.getKey().getVariables().values().contains(lib)) {
				results.add(entry.getValue().getMeasurementSet(MeasurementType.TIME).meanUnits()); //TODO Opgelet 
			}
		}
		return arrayMean(results);
	}
	

	private List<Double> getValuesList(String benchmark, String lib) {
		List<Double> results =  new ArrayList<Double>();
		
		for (Map.Entry<Scenario, ScenarioResult> entry : result.getRun().getMeasurements().entrySet()) {
			if (entry.getKey().getVariables().values().contains(benchmark)
					&& entry.getKey().getVariables().values().contains(lib)) {
				results.add(entry.getValue().getMeasurementSet(MeasurementType.TIME).meanUnits()); //TODO Opgelet 
			}
		}
		return results;
	}

	public Map<String, Double> parse(String benchmark, String[] libraries) {
		Map<String, Double> map = new HashMap<String, Double>();
		for (int i = 0; i < libraries.length; i++) {
			map.put(libraries[i], getBenchmarkMean(benchmark, libraries[i]));
		}
		return map;
	}

	public Map<String[], Double> parse(String[] benchmarks, String[] libraries) {
		Map<String[], Double> map = new HashMap<String[], Double>();
		for (int i = 0; i < libraries.length; i++) {
			for (int j = 0; j < benchmarks.length; j++) {
				map.put(new String[] {libraries[i], benchmarks[j]}, getBenchmarkMean(benchmarks[j], libraries[i]));
			}
		}
		return map;
	}

	public Map<String[], List<Double>> parseAndGetList(String[] benchmarks,
			String[] libraries) {
		Map<String[], List<Double>> map = new HashMap<String[], List<Double>>();
		for (int i = 0; i < libraries.length; i++) {
			for (int j = 0; j < benchmarks.length; j++) {
				map.put(new String[] {libraries[i], benchmarks[j]}, getValuesList(benchmarks[j], libraries[i]));
			}
		}
		return map;
	}

	public void print(String benchmark, String librarie) {
		for(Double a:getValuesList(benchmark, librarie)){
			System.out.println(a);
		}
	}


}
